#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "boyaa_socket.cpp"

using namespace std;

extern "C"  
{  
    #include "lua.h"  
    #include "lauxlib.h"  
    #include "lualib.h"  
}  

#if defined(_WIN32) || defined(_WIN64)
#define _DLLExport _declspec(dllexport)
#else
#define _DLLExport 
#endif

static int lua_create_memdb_client(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)lua_newuserdata(L, sizeof(CMemdbClient));
    *p = new CMemdbClient;
    luaL_getmetatable(L, "memdb_client");
    lua_setmetatable(L, -2);

    //printf("create p=%04x\n", p);
  
    return 1;
}

static int lua_connect_memdb(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    const char* host = luaL_checkstring(L, 2);
    int port = luaL_checkinteger(L, 3);
    bool flag =  (*p)->ConnectMemdb(host, port);

    lua_pushinteger(L, flag);

    return 1;
}

static int lua_send_memdb(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    void* buff = lua_touserdata(L, 2);
    int sz = luaL_checkinteger(L, 3);

    int send_sz =  (*p)->Send(buff, sz);

    lua_pushinteger(L, send_sz);

    return 1;
}

static int lua_recv_memdb(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int recv_sz =  (*p)->Recv();

    lua_pushlightuserdata(L, (*p)->m_recvBuf);
    lua_pushinteger(L, recv_sz);

    return 2;
}

static int lua_get_user_data(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int playerId = luaL_checkinteger(L, 2);
    std::string userData = (*p)->GetUserData(playerId);
    //std::cout<<"userData= "<<userData<<endl;

    lua_pushstring(L, userData.c_str());

    return 1;
}

static int lua_update_user_money(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int playerId = luaL_checkinteger(L, 2);
    long long money = luaL_checknumber(L, 3);
    
    int after_money = (*p)->UpdateUserMoney(playerId, money);

    lua_pushinteger(L, after_money);

    return 1;
}

static int lua_tarneeb_reset_user_money(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");

    int playerId = luaL_checkinteger(L, 2);
    long long money = luaL_checknumber(L, 3);
    int wmode = luaL_checkinteger(L, 4);
    
    int after_money = (*p)->TarneebResetUserMoney(playerId, money, wmode);

    lua_pushinteger(L, after_money);

    return 1;
}

static int lua_delete_base(lua_State* L)
{
    CMemdbClient** p = (CMemdbClient**)luaL_checkudata(L, 1, "memdb_client");
    luaL_argcheck(L, p != NULL, 1, "invalid user data");
    
    if (p) {
        //printf("delete p=%04x\n", p);
        delete *p;
    }

    return 1;
}

static const luaL_Reg registerInfo[] = {
    {"__gc", lua_delete_base},
   
    {"create_memdb_client", lua_create_memdb_client},
    {"connect_memdb", lua_connect_memdb},
    {"recv_memdb", lua_recv_memdb},
    {"send_memdb", lua_send_memdb},
    {"get_user_data", lua_get_user_data},
    {"update_user_money", lua_update_user_money},
    {"tarneeb_reset_user_money", lua_tarneeb_reset_user_money},

    {NULL, NULL}
};


extern "C" _DLLExport int luaopen_lua_memdb(lua_State *L)
{
    luaL_newmetatable(L, "memdb_client");
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");

	luaL_setfuncs(L, registerInfo, 0);

    return 1;
}
